import os
import sys
import time
import cPickle
import base64

import wave
import pyaudio
import StringIO

import Code.Util as Util

DATABASE = "D"
PLAY_ESPERA = "P"
PLAY_SINESPERA = "N"
STOP = "S"
TERMINAR = "T"

#=========================================================================================
class Orden :
    def __init__( self ) :
        self.clave = ""
        self.dv = {}

    def ponVar( self, nombre, valor ) :
        self.dv[nombre] = valor

    def bloqueEnvio( self ) :
        texto = base64.encodestring(cPickle.dumps(self.dv))
        return "%s%05d%s"%(self.clave, len(texto), texto )

    def dicTexto( self, texto ) :
        if texto :
            self.dv = cPickle.loads( base64.decodestring(texto) )
        else :
            self.dv = {}
        return self.dv

#=========================================================================================
class Replay( ) :

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def __init__( self ) :
        self.CHUNK = 1024

        self.dbw = {}
        self.lock = 0
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def procesa( self, io, orden ) :
        dv = orden.dv
        if orden.clave == DATABASE :
            fichero = dv["FICHERO"]
            tabla = dv["TABLA"]

            self.dbw = {} # como un reset
            self.add_db( fichero, tabla )
        elif orden.clave in (PLAY_ESPERA,PLAY_SINESPERA) :

            if "CLAVE" in dv :
                li = ( dv["CLAVE"], )
            else :
                li = dv["LISTACLAVES"]

            return self.play( io, li )

        return None

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def add_db( self, fichero, tabla ) :
        db = Util.DicDiskBlob( fichero, tabla )
        keys = db.keys()

        for k in keys :
            self.add_bin( k, db[k] )

        db.close()

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def add_bin( self, clave, bin ) :

        f = StringIO.StringIO( bin )
        self.add_wav( clave, f )

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def add_wav( self, clave, wav ) :

        wf = wave.open(wav, 'rb')

        if self.dbw is None :
            self.dbw = {}

        p = pyaudio.PyAudio()
        format = p.get_format_from_width(wf.getsampwidth())
        channels = wf.getnchannels()
        rate = wf.getframerate()
        p.terminate()

        self.dbw[clave] = ( format, channels, rate, wf.readframes( wf.getnframes() ) )
        wf.close()

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def siClave( self, clave ) :
        return clave in self.dbw

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    def play( self, io, liClaves ) :

        li = []
        for clave in liClaves :
            if clave in self.dbw :
                format, channels, rate, frames = self.dbw[clave]
                li.append( frames )
        frames = "".join(li)

        if not frames :
            return None

        p = pyaudio.PyAudio()
        stream = p.open( format = format, channels = channels, rate = rate, output = True )

        nTam = len(frames)
        nPos = 0
        orden = None

        for n in range(nTam) :
            hasta = nPos+self.CHUNK
            stream.write(frames[nPos:hasta])
            nPos = hasta
            orden = io.recibeOrden()
            if orden :
                if orden.clave in ( STOP, PLAY_SINESPERA, TERMINAR ) :
                    break

        if orden is None :
            stream.stop_stream()
        stream.close()
        p.terminate()

        return orden
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#=========================================================================================

#=========================================================================================
class IO() :
    def __init__( self, xcpu ) :
        self.newin = os.fdopen(sys.stdin.fileno(), 'r', 0)
        self.xcpu = xcpu

    def recibeOrden( self ) :
        try :
            self.newin.seek(0, os.SEEK_END)
        except :
            return None
        if self.newin.tell() >= 6 :
            self.newin.seek(0)
            while self.newin.read(1) != "#" :
                pass
            x = self.newin.read(6)
            orden = Orden()
            orden.clave = x[0]
            numero = int(x[1:6])
            if numero :
                orden.dicTexto( self.newin.read(numero) )
            return orden
        else :
            return None

    def run( self ) :
        orden = None
        while True :
            if orden :
                if orden.clave == TERMINAR :
                    break
                orden = self.xcpu.procesa( self, orden )
                if orden :
                    continue
            orden = self.recibeOrden()
            if orden is None :
                time.sleep( 0.1 )

#=========================================================================================

#=========================================================================================

def run() :
    ferr = open("bug.sound", "at")
    sys.stderr = ferr

    r = Replay()
    io = IO( r )
    io.run()

    ferr.close()
#=========================================================================================
